//--------------------------------------------------------------------------------
// This file is a portion of the PracticeEngine Rendering Engine.  It is distributed
// under the MIT License, available in the root of this distribution and 
// at the following URL:
//
// http://www.opensource.org/licenses/mit-license.php
//
// Copyright (c) Ferdinand Li 
//--------------------------------------------------------------------------------
#include "PCH.h"
#include "WinApp.h"
#include "DX11Renderer.h"
#include "Logger.h"

#pragma warning(push)
#pragma warning(disable:4996)

using namespace PracEng;

static double GSecondsPerCycle = 0.0;
static double GDeltaTime = 0.0;
static double GLastTime = 0.0;
static double GCurrentTime = 10.0;
static int GFps = 0;
static double GAccumulateTime = 0;
static int GCounter = 0;

WinApp* WinApp::m_App = NULL;

float GetGDeltaTimeSec(){ return GDeltaTime * 0.0001f; }


LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
{
	switch( msg )
	{	

	//case WM_CREATE: 
	//	{
	//		// Automatically return 0 to allow the window to proceed in the
	//		// creation process.

	//		return( 0 );
	//	} break;

	case WM_PAINT:
		{
			// This message is handled by the default handler to avoid a 
			// repeated sending of the message.  This results in the ability
			// to process all pending messages at once without getting stuck
			// in an eternal loop.
		} break;

	case WM_CLOSE:
		{
			// This message is sent when a window or an application should
			// terminate.
		} break;

	case WM_DESTROY: 
		{
			// This message is sent when a window has been destroyed.
			PostQuitMessage(0);
			return( 0 );
		} break;

	case WM_SIZE:
		{				
			
		} break;

	case WM_RBUTTONDOWN:
	case WM_MBUTTONDOWN:
	case WM_LBUTTONDOWN:
	case WM_RBUTTONDBLCLK:
	case WM_MBUTTONDBLCLK:
	case WM_LBUTTONDBLCLK:
		{
			WinApp::GetApp()->GetInputMgr()->UpdateMouseDown(hwnd, msg, wparam, lparam);
			
			return TRUE;
		}
	case WM_RBUTTONUP:
	case WM_MBUTTONUP:
	case WM_LBUTTONUP:
		{
			WinApp::GetApp()->GetInputMgr()->UpdateMouseUp(hwnd, msg, wparam, lparam);
		
			break;
		}
	case WM_CAPTURECHANGED:
		{
			if ((HWND)lparam != hwnd)
			{
				WinApp::GetApp()->GetInputMgr()->OnReleaseCapture();
				ReleaseCapture();
			}
			break;
		}
	case WM_MOUSEMOVE:
		{
			
		} break;

	case WM_MOUSEWHEEL:
		{
			
		} break;

	case WM_CHAR:
		{
			
		} break;

	case WM_KEYDOWN:
		{
			WinApp::GetApp()->GetInputMgr()->UpdateKeyStatesDown(wparam, lparam);
		} break;

	case WM_KEYUP:
		{
			WinApp::GetApp()->GetInputMgr()->UpdateKeyStatesUp(wparam, lparam);
		} break;
	}
	return( DefWindowProc( hwnd, msg, wparam, lparam ) );
}
WinApp* WinApp::GetApp()
{
	return m_App;
}

WinApp::WinApp()
{
	AllocConsole();
	freopen("CONOUT$", "w+t", stdout);
	freopen("CONIN$", "r+t", stdin);

	CaptionName = L"PraciceEngine";
	SizeX = 1280;
	SizeY = 720;
	m_App = this;
	m_Renderer = NULL;
}

WinApp::~WinApp()
{
	fclose(stdout);
	fclose(stdin);
	FreeConsole();
}

void WinApp::Initialize()
{
	PracEngLog(L"App Initialize!")
	InitWindow();
	InitRenderer();
	m_InputMgr = new InputManager;

	OnInit();
}

void WinApp::Update(double DeltaTime)
{
	
}

void WinApp::Exit()
{
	PracEngLog(L"App Exit!");
	OnExit();
	m_Renderer->Exit();

	if (m_Renderer)
	{
		delete m_Renderer;
	}

	if (m_InputMgr)
	{
		delete m_InputMgr;
	}

	if ( m_hWnd )
		DestroyWindow( m_hWnd );

	m_hWnd = 0;
}

void WinApp::Run()
{
	MSG msg = {0};

	while( WM_QUIT != msg.message )
	{

		if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
		else
		{
			GCurrentTime = GetCurrentTime();

			GDeltaTime = GCurrentTime - GLastTime;

			GAccumulateTime += GDeltaTime;
			if (GAccumulateTime >= 1000)
			{
				GFps = GCounter;
				GAccumulateTime = 0;
				GCounter = 0;
			}
			else
			{
				GCounter++;
			}

			Update(GDeltaTime/1000.0f);
			m_Renderer->Tick();

			GLastTime = GCurrentTime;
		}
		
	}
	
}


void PracEng::WinApp::OnInit()
{

}

void PracEng::WinApp::InitWindow()
{
	WNDCLASSEX wc;

	memset(&wc,0,sizeof(wc));
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = 0;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = L"PraticeEngine";
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	RegisterClassEx(&wc);

	RECT rc;
	rc.top = rc.left = 0;
	rc.right = SizeX;
	rc.bottom = SizeY;
	WindowStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
	AdjustWindowRect(&rc, WindowStyle, FALSE);

	long RealWidth = rc.right - rc.left;
	long RealHeight = rc.bottom - rc.top;

	m_hWnd = CreateWindowEx(
		NULL,
		wc.lpszClassName,
		CaptionName.c_str(),
		WindowStyle,
		0,
		0,
		RealWidth,
		RealHeight,
		NULL,
		NULL,
		NULL,
		NULL
		);

	if (m_hWnd)
	{
		ShowWindow( m_hWnd, SW_SHOWNORMAL );
		UpdateWindow( m_hWnd );
	}
}


void WinApp::OnExit()
{
	
}

void WinApp::InitRenderer()
{
	m_Renderer = new DX11Renderer(m_hWnd, SizeX, SizeY);
	m_Renderer->Initialize();
}

#pragma warning(pop)